#ifndef SHAREDPTR_H
#define SHAREDPTR_H

#include "Framework/Prerequisites.h"


namespace tyro
{
	namespace Framework
	{
		template< class T >
		class SharedPtr
		{
		protected:

			T*		ptr;
			UINT_32*	useCount;

		public:

			SharedPtr() : ptr(0), useCount(0) {}

			template< class Y>
			explicit SharedPtr(Y* rep)
				: ptr(rep)
				, useCount(0)
			{

			}



			SharedPtr(const SharedPtr& r)
				: ptr(0), useCount(0)
			{
				ptr = r.ptr;
				useCount = r.useCount;

				if (useCount)
				{
					++(*useCount);
				}
			}

			SharedPtr& operator =(const SharedPtr& sPtr)
			{
				if (ptr == sPtr.ptr)
				{
					return *this;
				}

				SharedPtr<T> tmp(sPtr);
				swap(tmp);
				return *this;
			}

			template< class Y>
			SharedPtr( const SharedPtr<Y>& r) : ptr(0), useCount(0)
			{
				ptr = r.GetPointer();
				useCount = r.GetUseCount();

				if (useCount)
				{
					++(*useCount);
				}
			}

			template < class Y >
			SharedPtr& operator=(const SharedPtr<Y>& r)
			{
				if (r->GetPointer())
				{
					return *this;
				}

				SharedPtr<T> tmp(r);
				swap(tmp);
				return *this;
			}



			inline T& operator*() const { return *ptr; }
			inline T* operator->() const { return ptr; }
			inline T* Get() const { return ptr; }
			void Bind(T* rep)
			{
				useCount = new UINT_32;
				ptr = rep;
			}

			inline T* GetPointer() const { return ptr; }
			inline UINT_32* GetUseCountPointer() const { return useCount; }
			inline bool IsNull(void) const { return ptr == 0; }
			inline void SetNull(void)
			{
				if (ptr)
				{
					ptr = 0;
					useCount = 0;
				}
			}
			
			

			
		protected:
			virtual void swap(SharedPtr<T> &other)
			{
					std::swap(ptr, other.ptr);
					std::swap(useCount, other.useCount);
			}
		};

		template< class T, class U > 
		inline bool operator == (SharedPtr<T> const& a, SharedPtr<U>& b)
		{
			return a.Get() == b.Get();
		}

		template<class T, class U> 
		inline bool operator!=(SharedPtr<T> const& a, SharedPtr<U> const& b)
		{
			return a.Get() != b.Get();
		}

		template<class T, class U> inline 
			bool operator<(SharedPtr<T> const& a, SharedPtr<U> const& b)
		{
			return std::less<const void*>()(a.Get(), b.Get());
		}

		

		


	}
}
#endif 